﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using Bmz.Laboratory.Workflow.Context;
using Bmz.Laboratory.Workflow.Entity;
using Bmz.Laboratory.Workflow.Enums;
using Bmz.Laboratory.Workflow.Repository;
using Bmz.Laboratory.Workflow.Service.Dto;

namespace Bmz.Laboratory.Workflow.Service
{
    public class FlowService : IFlowService
    {
        private readonly IRepository<FlowDbContext> _flowDbRepository;

        #region private function

        private bool OutRule(InstanceNode node, string userCode)
        {
            return node.TemplateNode.OutRule == TemplateNodeOutRuleEnum.Single ||
                   (node.TemplateNode.OutRule == TemplateNodeOutRuleEnum.All &&
                    !node.InstanceAccesses.Any(
                        p => p.Status == InstanceAccessStatusEnum.Submit && p.UserCode != userCode));
        }

        private bool InRule(InstanceNode currentInstanceNode, TemplateNode childTemplateNode)
        {
            var nodeCodeList = childTemplateNode.ParentNodes.Select(p => p.Code).ToList();
            nodeCodeList.Remove(currentInstanceNode.TemplateNodeCode);
            return childTemplateNode.InRule == TemplateNodeInRuleEnum.Single ||
                   (childTemplateNode.InRule == TemplateNodeInRuleEnum.All && this._flowDbRepository.DbContext.InstanceNodes.Any(p => p.IsEnable && nodeCodeList.Contains(p.TemplateNodeCode) && p.FlowdId == currentInstanceNode.FlowdId && p.Status != InstanceNodeStatusEnum.Finish));
        }

        #endregion

        public FlowService(IRepository<FlowDbContext> flowDbRepository)
        {
            this._flowDbRepository = flowDbRepository;
        }


        public bool NewFlow(string flowCode, string userCode)
        {
            //新建流程
            var templateFlow = this._flowDbRepository.GetEntityList<TemplateFlow>(p => p.Code == flowCode).FirstOrDefault();
            var instanceFlow = new InstanceFlow()
            {
                Id = flowCode + DateTime.Now.ToString("yyyyMMddhhmmss"),
                Status = InstanceFlowStatusEnum.Open,
                TemplateFlow = templateFlow,
            };
            this._flowDbRepository.Add(instanceFlow);

            //新建开始节点
            var rootNode = templateFlow.TemplateNodes.Where(p => p.FlowCode == flowCode && p.Type == TemplateNodeTypeEnum.Start).FirstOrDefault();
            var rootInstanceNode = new InstanceNode()
            {
                Id = rootNode.Code + DateTime.Now.ToString("yyyyMMddhhmmss"),
                Status = InstanceNodeStatusEnum.Finish,
                TemplateNode = rootNode,
                InstanceFlow = instanceFlow,
            };
            this._flowDbRepository.Add(rootInstanceNode);

            //新建访问权限
            var rootAccess = rootNode.TemplateNodeAccessPermissions.Select(p => p.TemplateAccess).FirstOrDefault();
            this._flowDbRepository.Add(new InstanceAccess()
            {
                UserCode = userCode,
                Status = InstanceAccessStatusEnum.Submit,
                TemplateAccess = rootAccess,
                InstanceNode = rootInstanceNode,
            });

            foreach (var item in rootNode.ChildNodes)
            {
                //新建节点
                var normalInstanceNode = new InstanceNode()
                {
                    Id = item.Code + DateTime.Now.ToString("yyyyMMddhhmmss"),
                    Status = InstanceNodeStatusEnum.Open,
                    TemplateNode = item,
                    InstanceFlow = instanceFlow,
                };
                this._flowDbRepository.Add(normalInstanceNode);
                //新建访问权限
                var normalAccess = item.TemplateNodeAccessPermissions.Select(p => p.TemplateAccess).FirstOrDefault();
                this._flowDbRepository.Add(new InstanceAccess()
                {
                    UserCode = userCode,//todo:normalAccess.object
                    Status = InstanceAccessStatusEnum.Initial,
                    TemplateAccess = normalAccess,
                    InstanceNode = normalInstanceNode,
                });
            }
            return this._flowDbRepository.Commit() > 0;
        }

        public bool TodoAction(string nodeId, string userCode)
        {
            var currentNode = this._flowDbRepository.GetEntityList<InstanceNode>(p => p.Id == nodeId).FirstOrDefault();
            var currentAccess = currentNode.InstanceAccesses.FirstOrDefault(p => p.UserCode == userCode);
            if (currentNode.Status != InstanceNodeStatusEnum.Open || currentAccess == null)
            {
                return false;
            }
            //当前节点办结
            if (OutRule(currentNode, userCode))
            {
                currentNode.Status = InstanceNodeStatusEnum.Finish;
                currentAccess.Status = InstanceAccessStatusEnum.Submit;
                if (currentNode.TemplateNode.Type == TemplateNodeTypeEnum.End)
                {
                    currentNode.InstanceFlow.Status = InstanceFlowStatusEnum.Finish;
                }
            }

            if (currentNode.Status == InstanceNodeStatusEnum.Finish && currentNode.InstanceFlow.Status != InstanceFlowStatusEnum.Finish)
            {
                foreach (var item in currentNode.TemplateNode.ChildNodes)
                {
                    if (InRule(currentNode, item))
                    {
                        //新建节点
                        var normalInstanceNode = new InstanceNode()
                        {
                            Id = item.Code + DateTime.Now.ToString("yyyyMMddhhmmss"),
                            Status = InstanceNodeStatusEnum.Open,
                            TemplateNode = item,
                            InstanceFlow = currentNode.InstanceFlow,
                        };
                        this._flowDbRepository.Add(normalInstanceNode);
                        //新建访问权限
                        var normalAccess = item.TemplateNodeAccessPermissions.Select(p => p.TemplateAccess).FirstOrDefault();
                        this._flowDbRepository.Add(new InstanceAccess()
                        {
                            UserCode = userCode,//todo:normalAccess.object
                            Status = InstanceAccessStatusEnum.Initial,
                            TemplateAccess = normalAccess,
                            InstanceNode = normalInstanceNode,
                        });
                    }
                }
            }
            return this._flowDbRepository.Commit() > 0;
        }

        public IEnumerable<TodoDto> GetTodoListByUser(string userCode)
        {
            var query = this._flowDbRepository.DbContext.InstanceNodes.Where(
                        p => p.InstanceAccesses.Any(x => x.UserCode == userCode && x.IsEnable)&&p.Status== InstanceNodeStatusEnum.Open)
                        .Select(p => new TodoDto()
                        {
                            NodeId = p.Id,
                            NodeName = p.TemplateNode.Name,
                            Url = p.TemplateNode.Url
                        });
            return query.ToList();
        }
    }
}
